package com.xbongbong.paas.elasticsearch.model.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormSubDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.constant.EsNormalConstant;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.model.PaasFormSubDataEsModel;
import com.xbongbong.paas.elasticsearch.pojo.QueryListVO;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.pojo.dto.DeleteDTO;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.FormSubDataUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.pojo.dto.PhysicalDeleteDTO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.domain.entity.UpdateDataValueEntity;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.knowledge.base.pojo.dto.KnowledgeEsAddDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.UpdateStockDataEntity;
import com.xbongbong.saas.domain.entity.WorkOrderEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerCommunicateEntityExt;
import com.xbongbong.saas.domain.entity.ext.PayPlanSheetEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.enums.CustomerStatementSnapshotEnum;
import com.xbongbong.saas.enums.subform.BomTeamEnum;
import com.xbongbong.saas.enums.subform.ClueTeamEnum;
import com.xbongbong.saas.enums.subform.CommunicatePlanTeamEnum;
import com.xbongbong.saas.enums.subform.CompetitorTeamEnum;
import com.xbongbong.saas.enums.subform.ContactTeamEnum;
import com.xbongbong.saas.enums.subform.ContractPerformanceSubFormEnum;
import com.xbongbong.saas.enums.subform.ContractProductSubFormEnum;
import com.xbongbong.saas.enums.subform.ContractTeamEnum;
import com.xbongbong.saas.enums.subform.CustomerTeamEnum;
import com.xbongbong.saas.enums.subform.DefaultTeamEnum;
import com.xbongbong.saas.enums.subform.MarketActivityTeamEnum;
import com.xbongbong.saas.enums.subform.OpportunityTeamEnum;
import com.xbongbong.saas.enums.subform.PaasTeamEnum;
import com.xbongbong.saas.enums.subform.PayBalanceTeamEnum;
import com.xbongbong.saas.enums.subform.PayPlanSheetTeamEnum;
import com.xbongbong.saas.enums.subform.PayPlanTeamEnum;
import com.xbongbong.saas.enums.subform.PaymentBalanceTeamEnum;
import com.xbongbong.saas.enums.subform.PaymentSheetTeamEnum;
import com.xbongbong.saas.enums.subform.PaymentTaskTeamEnum;
import com.xbongbong.saas.enums.subform.PaymentTeamEnum;
import com.xbongbong.saas.enums.subform.ProductStockSubFormEnum;
import com.xbongbong.saas.enums.subform.ProductTeamEnum;
import com.xbongbong.saas.enums.subform.ProductWarehouseSubFormEnum;
import com.xbongbong.saas.enums.subform.ProductionOrderTeamEnum;
import com.xbongbong.saas.enums.subform.PurchaseTeamEnum;
import com.xbongbong.saas.enums.subform.QuotationTeamEnum;
import com.xbongbong.saas.enums.subform.RefundTeamEnum;
import com.xbongbong.saas.enums.subform.SupplierContactTeamEnum;
import com.xbongbong.saas.enums.subform.SupplierTeamEnum;
import com.xbongbong.saas.enums.subform.WorkOrderCcTeamEnum;
import com.xbongbong.saas.enums.subform.WorkOrderTeamEnum;
import lombok.SneakyThrows;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;


/**
 * @author 梁鲁江
 * @since
 * @version
 */
@Service("paasEsModel")
public class PaasEsModelImpl implements PaasEsModel {
    private static final Logger LOG = LoggerFactory.getLogger(PaasEsModelImpl.class);

    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private PaasFormSubDataEsModel paasFormSubDataEsModel;

    @Override
    public void insert(InsertDTO insertDTO) throws XbbException {
        try {
            IndexRequest indexRequest = getIndexRequest(insertDTO);
            RestHighLevelClient restHighLevelClient = xbbElasticsearchRestTemplate.getRestHighLevelClient(insertDTO.getIndex());
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
      /*      String index = indexResponse.getIndex();
            String id = indexResponse.getId();
            if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {

            } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {

            }
            ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
            if (shardInfo.getTotal() != shardInfo.getSuccessful()) {

            }
            if (shardInfo.getFailed() > 0) {
                for (ReplicationResponse.ShardInfo.Failure failure :
                        shardInfo.getFailures()) {
                    String reason = failure.reason();
                }
            }*/
            //可以提供异步
          /*  ActionListener<IndexResponse> listener = new ActionListener<IndexResponse>() {
                @Override
                public void onResponse(IndexResponse indexResponse) {

                }

                @Override
                public void onFailure(Exception e) {

                }
            };
            restHighLevelClient.indexAsync(indexRequest, RequestOptions.DEFAULT,listener);*/
        } catch (Exception e) {
            LOG.error("es插入报错",e);
            LOG.error(insertDTO.toString());
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void insertBatch(List<InsertDTO> insertList) throws XbbException  {
        if(CollectionsUtil.isEmpty(insertList)){
            return;
        }
        insertBatch(insertList, WriteRequest.RefreshPolicy.WAIT_UNTIL);
    }

    @Override
    public void insertBatch(List<InsertDTO> insertList, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException  {
        insertBatch(insertList,refreshPolicy,true);
    }
    @Override
    public void insertBatch(List<InsertDTO> insertList, WriteRequest.RefreshPolicy refreshPolicy,boolean needThrow) throws XbbException  {
        insertBatch(insertList,refreshPolicy,needThrow,true);
    }
    @Override
    public void insertBatch(List<InsertDTO> insertList, WriteRequest.RefreshPolicy refreshPolicy,boolean needThrow,boolean needJoinField) throws XbbException  {
        if(CollectionsUtil.isEmpty(insertList)){
            return;
        }
        try {
            //手动处理单次索引量
            for (int i = 0; i < insertList.size(); i += EsNormalConstant.INSERT_NUM) {
                int toIndex = i +  EsNormalConstant.INSERT_NUM;
                if (toIndex > insertList.size()) {
                    toIndex = insertList.size();
                }
                List<InsertDTO> newList = insertList.subList(i, toIndex);
                if (newList != null && !newList.isEmpty()) {
                    BulkRequest bulkRequest = getBulkRequest(refreshPolicy);
                    for (InsertDTO insertDTO : newList) {
                        //批量必须 指定不刷新
                        IndexRequest indexRequest;
                        if(needJoinField){
                            indexRequest = getIndexRequest(insertDTO);
                        }else {
                            indexRequest = getIndexRequest(insertDTO,false);
                        }
                        bulkRequest.add(indexRequest);
                    }
                    bulk(bulkRequest,needThrow,newList.get(0).getIndex());
                }
            }
        } catch (Exception e) {
            LOG.error("es批量插入报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void insertBatchAsync(List<InsertDTO> insertList, WriteRequest.RefreshPolicy refreshPolicy, boolean needThrow) throws XbbException {
        if(CollectionsUtil.isEmpty(insertList)){
            return;
        }
        try {
            //手动处理单次索引量
            for (int i = 0; i < insertList.size(); i += EsNormalConstant.INSERT_NUM) {
                int toIndex = i +  EsNormalConstant.INSERT_NUM;
                if (toIndex > insertList.size()) {
                    toIndex = insertList.size();
                }
                List<InsertDTO> newList = insertList.subList(i, toIndex);
                if (newList != null && !newList.isEmpty()) {
                    BulkRequest bulkRequest = getBulkRequest(refreshPolicy);
                    for (InsertDTO insertDTO : newList) {
                        // TODO 批量必须 指定不刷新
                        IndexRequest indexRequest = getIndexRequest(insertDTO);
                        bulkRequest.add(indexRequest);
                    }
                    bulkAsync(bulkRequest,needThrow,newList.get(0).getIndex());
                }
            }
        } catch (Exception e) {
            LOG.error("es批量插入报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void update(InsertDTO insertDTO) throws XbbException {
        UpdateRequest updateRequest = getUpdateRequest(insertDTO);
        update(updateRequest);
    }

    @Override
    public void updateBatch(List<InsertDTO> insertList) throws XbbException {
        updateBatch(insertList, WriteRequest.RefreshPolicy.WAIT_UNTIL);
    }

    @Override
    public void updateBatch(List<InsertDTO> insertList, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        updateBatch(insertList,  refreshPolicy,true);
    }

    @Override
    public void updateBatch(List<InsertDTO> insertList, WriteRequest.RefreshPolicy refreshPolicy, boolean needThrow) throws XbbException {
        if(CollectionsUtil.isEmpty(insertList)){
            return;
        }
        try {
            //手动处理单次索引量
            for (int i = 0; i < insertList.size(); i += EsNormalConstant.INSERT_NUM) {
                int toIndex = i +  EsNormalConstant.INSERT_NUM;
                if (toIndex > insertList.size()) {
                    toIndex = insertList.size();
                }
                List<InsertDTO> newList = insertList.subList(i, toIndex);
                if (newList != null && !newList.isEmpty()) {
                    BulkRequest bulkRequest = getBulkRequest(refreshPolicy);
                    for (InsertDTO insertDTO : newList) {
                        insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
                        UpdateRequest updateRequest = getUpdateRequest(insertDTO);
                        bulkRequest.add(updateRequest);
                    }
                    bulk(bulkRequest,needThrow,newList.get(0).getIndex());
                }
            }
        } catch (Exception e) {
            LOG.error("es批量插入报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void deleteBatch(List<Long> list, String corpid, Integer del, IndexTypeEnum indexTypeEnum) throws XbbException {
        deleteBatch(list, corpid, del, indexTypeEnum, null);
    }

    @Override
    public void deleteBatch(List<Long> list, String corpid, Integer del, IndexTypeEnum indexTypeEnum, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        try {
            List<InsertDTO> insertList = new ArrayList<>();
            for (Long item : list) {
                InsertDTO insertDTO = new InsertDTO();
                if (IndexTypeEnum.isSubform(indexTypeEnum)) {
                    insertDTO.setEsId(indexTypeEnum.getType() + "_" + corpid + "_" + item);
                } else {
                    insertDTO.setEsId(corpid + "_" + item);
                }
                Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                map.put("del", del);
                map.put("updateTime", DateUtil.getInt());
                insertDTO.setSource(map);
                insertDTO.setIndexTypeEnum(indexTypeEnum);
                insertList.add(insertDTO);
            }
            if(refreshPolicy == null){
                updateBatch(insertList);
            }else{
                updateBatch(insertList, refreshPolicy);
            }
        } catch (Exception e) {
            LOG.error("es批量删除报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void physicalDeleteBatch(List<Long> list, String corpid, IndexTypeEnum indexTypeEnum) throws XbbException {
        try {
            //TODO
            List<DeleteDTO> deleteList = new ArrayList<>();
            for (Long item : list) {
                DeleteDTO deleteDTO = new DeleteDTO();
                deleteDTO.setEsId(corpid + "_" + item);
                deleteDTO.setIndexTypeEnum(indexTypeEnum);
                deleteList.add(deleteDTO);
            }
            for (int i = 0; i < deleteList.size(); i += EsNormalConstant.INSERT_NUM) {
                int toIndex = i +  EsNormalConstant.INSERT_NUM;
                if (toIndex > deleteList.size()) {
                    toIndex = deleteList.size();
                }
                List<DeleteDTO> newList = deleteList.subList(i, toIndex);
                if (newList != null && !newList.isEmpty()) {
                    BulkRequest bulkRequest = getBulkRequest();
                    for (DeleteDTO deleteDTO : newList) {
                        deleteDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
                        DeleteRequest deleteRequest = getDeleteRequest(deleteDTO);
                        bulkRequest.add(deleteRequest);
                    }
                    bulk(bulkRequest,newList.get(0).getIndexTypeEnum().getIndex());
                }
            }
        } catch (Exception e) {
            LOG.error("es批量物理删除报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

    }
    @Override
    public void physicalDeleteBatchChild(List<DeleteDTO> deleteList, String corpid, IndexTypeEnum indexTypeEnum) throws XbbException {
        try {
            //TODO
            if(CollectionsUtil.isEmpty(deleteList)){
                return;
            }
            for (int i = 0; i < deleteList.size(); i += EsNormalConstant.INSERT_NUM) {
                int toIndex = i +  EsNormalConstant.INSERT_NUM;
                if (toIndex > deleteList.size()) {
                    toIndex = deleteList.size();
                }
                List<DeleteDTO> newList = deleteList.subList(i, toIndex);
                if (newList != null && !newList.isEmpty()) {
                    BulkRequest bulkRequest = getBulkRequest();
                    for (DeleteDTO deleteDTO : newList) {
                        deleteDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
                        DeleteRequest deleteRequest = getDeleteRequest(deleteDTO);
                        bulkRequest.add(deleteRequest);
                    }
                    bulk(bulkRequest,newList.get(0).getIndexTypeEnum().getIndex());
                }
            }
        } catch (Exception e) {
            LOG.error("es批量物理删除报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

    }

    /**
     * Description: 物理删除子表单数据
     * @param corpid
     * @param subDataEntities
     * @param indexTypeEnum
     * @return void
     * @throws
     * @author 魏荣杰
     * @date 2020/9/30 15:35
     * @since
     */
    @Override
    public void physicalDeleteSubBatch(String corpid, List<? extends PaasFormSubDataEntity> subDataEntities, IndexTypeEnum indexTypeEnum) throws XbbException {
        if (CollectionUtils.isEmpty(subDataEntities)) {
            return;
        }
        List<DeleteDTO> deleteSubList = new ArrayList<>();
        for (PaasFormSubDataEntity paasFormSubDataEntity : subDataEntities) {
            DeleteDTO deleteDTO = new DeleteDTO();
            deleteDTO.setEsId(corpid + "_" + paasFormSubDataEntity.getId());
            deleteDTO.setIndexTypeEnum(indexTypeEnum);
            deleteDTO.setParent(corpid + "_" + paasFormSubDataEntity.getDataId());
            deleteSubList.add(deleteDTO);
        }
        physicalDeleteBatchChild(deleteSubList, corpid, indexTypeEnum);
    }

    @Override
    public void updateBatchMuchField(List<UpdateDataEntity> jsonArray, IndexTypeEnum  indexTypeEnum) throws XbbException {
        if(CollectionsUtil.isEmpty(jsonArray)){
            return;
        }
        List<InsertDTO> insertList = new ArrayList<>();
        for (UpdateDataEntity updateDataEntity : jsonArray) {
            InsertDTO insertDTO = getInsertDTOForUpdateEntity(updateDataEntity, indexTypeEnum);
            insertList.add(insertDTO);
        }
        updateBatch(insertList);
    }
    @Override
    public void updateBatchMuchField(List<UpdateDataEntity> jsonArray, IndexTypeEnum  indexTypeEnum,boolean needThrow) throws XbbException {
        if(CollectionsUtil.isEmpty(jsonArray)){
            return;
        }
        List<InsertDTO> insertList = new ArrayList<>();
        for (UpdateDataEntity updateDataEntity : jsonArray) {
            InsertDTO insertDTO = getInsertDTOForUpdateEntity(updateDataEntity, indexTypeEnum);
            insertList.add(insertDTO);
        }
        updateBatch(insertList,WriteRequest.RefreshPolicy.WAIT_UNTIL,needThrow);
    }

    @Override
    public void updateBatchMuchField(List<UpdateDataEntity> jsonArray, IndexTypeEnum  indexTypeEnum, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        if(CollectionsUtil.isEmpty(jsonArray)){
            return;
        }
        List<InsertDTO> insertList = new ArrayList<>();
        for (UpdateDataEntity updateDataEntity : jsonArray) {
            InsertDTO insertDTO = getInsertDTOForUpdateEntity(updateDataEntity, indexTypeEnum);
            insertList.add(insertDTO);
        }
        updateBatch(insertList, refreshPolicy);
    }

    @Override
    public void updateBySingle(UpdateDataEntity jsonArray, IndexTypeEnum  indexTypeEnum) throws XbbException {
        if(jsonArray==null){
            return;
        }
        InsertDTO insertDTO = getInsertDTOForUpdateEntity(jsonArray, indexTypeEnum);
        update(insertDTO);
    }


    @Override
    public void delete(DeleteDTO deleteDTO) throws XbbException {
        delete(deleteDTO, DelEnum.DELETE);
    }

    @Override
    public void delete(DeleteDTO deleteDTO, DelEnum delEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        BeanUtil.copyProperties(deleteDTO, insertDTO);
        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //此处可以扩展
        map.put("del", delEnum.getDel());
        map.put("updateTime", DateTimeUtil.getInt());
        insertDTO.setSource(map);
        update(insertDTO);
    }

    @Override
    public InsertDTO getSaveDTO(PaasFormDataEntity paasFormDataEntity, IndexTypeEnum indexTypeEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        paasFormDataEntity.setDataId(paasFormDataEntity.getId());
        String routing = null;
        Map<String, Object> source = BeanUtil.convertBean2Map(paasFormDataEntity, true, true);
        switch (indexTypeEnum) {
            case IDX_SAAS_CUSTOMER_TEAM:
            case IDX_SAAS_CUSTOMER_TEAM_SPECIAL:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(CustomerTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_CONTRACT_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ContractTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_QUOTATION_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(QuotationTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_CONTACT_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ContactTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_PAYMENT_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PaymentTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_PAYMENT_TASK_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PaymentTaskTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_PAYMENT_SHEET_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PaymentSheetTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_PRODUCTION_ORDER_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ProductionOrderTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_PAY_PLAN_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PayPlanTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_COMMUNICATE_PLAN_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(CommunicatePlanTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_OPPORTUNITY_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(OpportunityTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_BOM_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(BomTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_PURCHASE_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PurchaseTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_SUPPLIER_CONTACT_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(SupplierContactTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_SUPPLIER_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(SupplierTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_PRODUCT_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ProductTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_REFUND_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(RefundTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_WORK_ORDER_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(WorkOrderTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_WORK_ORDER_CC:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(WorkOrderCcTeamEnum.WORKORDER_ID.getDataAttr());
                break;
            case IDX_PAYMENT_BALANCE_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PaymentBalanceTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_PAY_BALANCE_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PayBalanceTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_CONTRACT_PRODUCT:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ContractProductSubFormEnum.CONTRACT_ID.getDataAttr());
                break;
            case IDX_SAAS_CONTRACT_PERFORMANCE:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ContractPerformanceSubFormEnum.CONTRACT_ID.getDataAttr());
                break;
            case IDX_SAAS_PRODUCT_WAREHOUSE:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ProductWarehouseSubFormEnum.PRODUCT_ID.getDataAttr());
                break;
            case IDX_SAAS_PRODUCT_STOCK_INFO:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ProductStockSubFormEnum.PRODUCT_ID.getDataAttr());
                break;
            case IDX_SAAS_PAYPLAN_SHEET_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PayPlanSheetTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_CLUE_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(ClueTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_MARKET_ACTIVITY_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(MarketActivityTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_CUSTOMER_STATEMENT_SNAPSHOT:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(CustomerStatementSnapshotEnum.SUMMARY_ID.getAttr());
                break;
            case IDX_FORM_DATA_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(PaasTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SLA_LOG_DATA_TEAM:
                // 此处索引使用默认枚举 DefaultTeamEnum
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(DefaultTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_WORK_ORDER_V2_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(DefaultTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_WORK_ORDER_V2_PRODUCT:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(DefaultTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_RECEIPT_ORDER_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(DefaultTeamEnum.DATA_ID.getDataAttr());
                break;
            case IDX_SAAS_COMPETITOR_TEAM:
                routing = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getData().get(CompetitorTeamEnum.DATA_ID.getDataAttr());
                break;
            default:
                break;
        }
        String relations =null;
        String esId;
        if(StringUtil.isNotEmpty(routing)){
            insertDTO.setParent(routing);
            relations = "{\"name\":\"" + indexTypeEnum.getType() + "\",\"parent\":\"" + routing  +"\"}";
            source.put(ElasticConstant.MY_JOIN_FIELD,  (JSONObject) JSONObject.parse(relations));
            esId = indexTypeEnum.getType()+ "_" + paasFormDataEntity.getCorpid() +"_"+ + paasFormDataEntity.getId();
        }else{
            source.put(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType());
            esId = paasFormDataEntity.getCorpid() + "_" + paasFormDataEntity.getId();
        }
        insertDTO.setEsId(esId);
        insertDTO.setSource(source);
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        return insertDTO;
    }

    @Override
    public InsertDTO getSaveDTO(CustomerCommunicateEntityExt customerCommunicateEntityExt, IndexTypeEnum indexTypeEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(customerCommunicateEntityExt.getCorpid() + "_" + customerCommunicateEntityExt.getId());
        customerCommunicateEntityExt.setDataId(customerCommunicateEntityExt.getId());
        insertDTO.setSource(BeanUtil.convertBean2Map(customerCommunicateEntityExt, true, true));
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        return insertDTO;
    }

    @Override
    public InsertDTO getSaveDTO(WorkOrderEntity workOrderEntity, IndexTypeEnum indexTypeEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(workOrderEntity.getCorpid() + "_" + workOrderEntity.getId());
        workOrderEntity.setDataId(workOrderEntity.getId());
        insertDTO.setSource(BeanUtil.convertBean2Map(workOrderEntity, true, true));
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        return insertDTO;
    }

    @Override
    public InsertDTO getSaveDTO(KnowledgeEsAddDTO knowledgeEsAddDTO, IndexTypeEnum indexTypeEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(knowledgeEsAddDTO.getCorpid() + "_" + knowledgeEsAddDTO.getId());
        //knowledgeDataEntity.setDataId(knowledgeDataEntity.getId());
        insertDTO.setSource(BeanUtil.convertBean2Map(knowledgeEsAddDTO, true, true));
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        return insertDTO;
    }

    @Override
    public InsertDTO getSaveDTO(PaymentSheetEntityExt paymentSheetEntityExt, IndexTypeEnum indexTypeEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(paymentSheetEntityExt.getCorpid() + "_" + paymentSheetEntityExt.getId());
        paymentSheetEntityExt.setDataId(paymentSheetEntityExt.getId());
        insertDTO.setSource(BeanUtil.convertBean2Map(paymentSheetEntityExt, true, true));
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        return insertDTO;
    }

    @Override
    public InsertDTO getSaveDTO(PayPlanSheetEntityExt payPlanSheetEntityExt, IndexTypeEnum indexTypeEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(payPlanSheetEntityExt.getCorpid() + "_" + payPlanSheetEntityExt.getId());
        payPlanSheetEntityExt.setDataId(payPlanSheetEntityExt.getId());
        insertDTO.setSource(BeanUtil.convertBean2Map(payPlanSheetEntityExt, true, true));
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        return insertDTO;
    }

    @Override
    public InsertDTO getSaveDTO(PaasFormSubDataEntity paasFormSubDataEntity, IndexTypeEnum indexTypeEnum) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(paasFormSubDataEntity.getCorpid() + "_" + paasFormSubDataEntity.getId());
        Map<String, Object> source = BeanUtil.convertBean2Map(paasFormSubDataEntity, true, true);
        String routing = paasFormSubDataEntity.getCorpid() + "_" + paasFormSubDataEntity.getDataId();
        String relations = "{\"name\":\"" + indexTypeEnum.getType() + "\",\"parent\":\"" + routing  +"\"}";
        source.put(ElasticConstant.MY_JOIN_FIELD, JSONObject.parse(relations));
        insertDTO.setParent(routing);
        insertDTO.setSource(source);
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        return insertDTO;
    }

    @Override
    public <T> void insert(T entity, IndexTypeEnum indexTypeEnum, String corpid, Long id, Long parentId) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(corpid + "_" + id);
        if (!Objects.isNull(parentId)){
            insertDTO.setParent(corpid + "_" + parentId);
        }
        insertDTO.setSource(BeanUtil.convertBean2Map(entity, true, true));
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        insert(insertDTO);
    }

    @Override
    public <T> void update(T entity, IndexTypeEnum indexTypeEnum, String corpid, Long id, Long parentId) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(corpid + "_" + id);
        if (!Objects.isNull(parentId)){
            insertDTO.setParent(corpid + "_" + parentId);
        }
        insertDTO.setSource(BeanUtil.convertBean2Map(entity, true, true));
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        update(insertDTO);
    }

    @Override
    public void delete(Long id, String corpid, IndexTypeEnum indexTypeEnum, Long parentId) throws XbbException {
        InsertDTO insertDTO = new InsertDTO();
        if (IndexTypeEnum.isSubform(indexTypeEnum)) {
            insertDTO.setEsId(indexTypeEnum.getType() + "_" + corpid + "_" + id);
        } else {
            insertDTO.setEsId(corpid + "_" + id);
        }
        if (!Objects.isNull(parentId)){
            insertDTO.setParent(corpid + "_" + parentId);
        }
        Map<String,Object> map = new HashMap<>(16);
        map.put("del",1);
        map.put("updateTime",DateTimeUtil.getInt());
        insertDTO.setSource(map);
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        update(insertDTO);
    }

    @Override
    public void physicalDelete(PhysicalDeleteDTO physicalDeleteDTO) throws XbbException {
        physicalDelete(physicalDeleteDTO.getEsId(),physicalDeleteDTO.getIndex(),physicalDeleteDTO.getType());
    }



    @Override
    public void physicalDelete(Long id, String corpid, IndexTypeEnum indexTypeEnum, Long parentId) throws XbbException {
        physicalDelete(corpid + "_" + id,indexTypeEnum.getIndex(),indexTypeEnum.getType());
    }

    @Override
    public PaasFormDataEntityExt getByKey(Long id, String corpid, IndexTypeEnum indexTypeEnum,List<String> fieldList) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termQuery("dataId",id));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        //限定返回值
        if(CollectionsUtil.isNotEmpty(fieldList)){
            EsUtil.setFieldList(sourceBuilder, fieldList);
        }
        //分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);
        if (esEntities == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        List<PaasFormDataEntityExt> resultList = esEntities.getContent();
        if(CollectionsUtil.isNotEmpty(resultList)){
            return resultList.get(0);
        }
        return null;
    }

    @Override
    public List<PaasFormDataEntityExt> getByIdList(Collection<Long> idIn, String corpid, Integer saasMark, Integer businessType, Collection<String> fieldList, IndexTypeEnum indexTypeEnum) throws XbbException {
        if (CollectionsUtil.isEmpty(idIn)) {
            return new ArrayList<>();
        }
        // 脏数据，过滤掉null值，防止ES查询报错
        idIn = idIn.stream().filter(Objects::nonNull).collect(Collectors.toList());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery("dataId",idIn));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        //限定返回值
        if(CollectionsUtil.isNotEmpty(fieldList)){
            EsUtil.setFieldList(sourceBuilder, new ArrayList<>(fieldList));
        }
        //分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, idIn.size());
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);
        if (esEntities == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        List<PaasFormDataEntityExt> resultList = esEntities.getContent();
        return resultList;
    }


    @Override
    public <T> List<T> getByIdList(Collection<Long> idIn, String corpid, Collection<String> fieldList, IndexTypeEnum indexTypeEnum, Class<T> clazz) throws XbbException {
        if (CollectionsUtil.isEmpty(idIn)) {
            return new ArrayList<>();
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery("dataId",idIn));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        //限定返回值
        if(CollectionsUtil.isNotEmpty(fieldList)){
            EsUtil.setFieldList(sourceBuilder, new ArrayList<>(fieldList));
        }
        //分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, idIn.size());
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<T> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, clazz);
        if (esEntities == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return esEntities.getContent();
    }

    @Override
    public InsertDTO getInsertDTOForUpdateEntity(UpdateDataEntity jsonArray, IndexTypeEnum indexTypeEnum) {
        InsertDTO insertDTO = new InsertDTO();
        Map<String,Object> source= new HashMap(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<UpdateDataValueEntity> list = jsonArray.getData();
        if(CollectionsUtil.isNotEmpty(list)){
            JSONObject dataSource= new JSONObject();
            for(UpdateDataValueEntity data: list){
                String esKey = data.getEsKey();
                Object value = data.getValue();
                if(StringUtil.isEmpty(esKey)){
                    continue;
                }
                if(esKey.contains("data.")){
                    esKey =  esKey.replace("data.", "");
                    if (CollectionsUtil.isNotEmpty(data.getSubDataList()) && esKey.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                        // 子表单更新
//                    List<List<UpdateSubDataValueEntity>> subDataList = data.getSubDataList();
//                    JSONArray result = new JSONArray();
//                    for (int i = 0; i < subDataList.size(); i++) {
//                        List<UpdateSubDataValueEntity> subValueList = subDataList.get(i);
//                        JSONObject resultObject = new JSONObject();
//                        for (UpdateSubDataValueEntity valueItem : subValueList) {
//                            resultObject.put(valueItem.getEsKey(), valueItem.getValue());
//                        }
//                        result.add(resultObject);
//                    }
//                    dataSource.put(esKey, result);
                    } else {
                        dataSource.put(esKey,value);
                    }
                }else {
                    source.put(esKey,value);
                }
            }
            source.put("data",dataSource);
        }
        if (Objects.nonNull(jsonArray.getDel())) {
            source.put("del",jsonArray.getDel());
        }
        //TODO haibin.zhang 用完删
        if (Objects.nonNull(jsonArray.getOwnerId())){
            source.put("ownerId",jsonArray.getOwnerId());
        }
        if (Objects.nonNull(jsonArray.getMenuId())){
            source.put("menuId",jsonArray.getMenuId());
        }
        if (Objects.nonNull(jsonArray.getUpdateTime())) {
            source.put("updateTime",jsonArray.getUpdateTime());
        }
        if (Objects.nonNull(jsonArray.getFlowStatus())) {
            source.put("flowStatus",jsonArray.getFlowStatus());
        }
        if (Objects.nonNull(jsonArray.getSerialNo())){
            source.put("serialNo",jsonArray.getSerialNo());
        }
        if (Objects.nonNull(jsonArray.getDepartmentId())){
            source.put("departmentId",jsonArray.getDepartmentId());
        }
        insertDTO.setSource(source);
        insertDTO.setIndexTypeEnum(indexTypeEnum);
        insertDTO.setEsId(jsonArray.getCorpid()+"_"+jsonArray.getId());
        return insertDTO;
    }

    @Override
    public List<PaasFormDataEntityExt> list(SearchSourceBuilder sourceBuilder, IndexTypeEnum indexTypeEnum, List<String> fieldList, Integer page, Integer pageSize) throws XbbException {
        // 传空数组，可以查全字段
        if (Objects.isNull(fieldList)) {
            fieldList = new ArrayList<>();
            fieldList.add(StringConstant.DATA_ID);
        }
        EsUtil.setFieldList(sourceBuilder, fieldList);
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        PageRequest  pageRequest= EsUtil.setPage(sourceBuilder, page, pageSize);
        List<PaasFormDataEntityExt> formDataList = xbbElasticsearchRestTemplate.queryForList(pageRequest, searchRequest,PaasFormDataEntityExt.class);
        return formDataList;
    }

    @Override
    public void updateBatchDataByType(List<UpdateStockDataEntity> updateDataList, IndexTypeEnum indexTypeEnum) throws XbbException {
        List<InsertDTO> insertList = new ArrayList<>();
        for (UpdateStockDataEntity updateStockDataEntity : updateDataList) {
            InsertDTO insertDTO = new InsertDTO();
            Map<String,Object> source= new HashMap(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (Objects.nonNull(updateStockDataEntity.getAppId())) {
                source.put("appId",updateStockDataEntity.getAppId());
            }
            if (Objects.nonNull(updateStockDataEntity.getMenuId())) {
                source.put("menuId",updateStockDataEntity.getMenuId());
            }
            if (Objects.nonNull(updateStockDataEntity.getFormId())) {
                source.put("formId",updateStockDataEntity.getFormId());
            }
            insertDTO.setSource(source);
            insertDTO.setIndexTypeEnum(indexTypeEnum);
            insertDTO.setEsId(updateStockDataEntity.getCorpid()+"_"+updateStockDataEntity.getId());
            insertList.add(insertDTO);
        }
        updateBatch(insertList);
    }



    @Override
    public PaasFormDataEsListVO list(IndexTypeEnum indexTypeEnum, Integer businessType, SearchSourceBuilder sourceBuilder, List<String> fieldList,
                                      Integer page, Integer pageSize) throws XbbException {
        PaasFormDataEsListVO formDataListVO = new PaasFormDataEsListVO();
        //限定返回值
        EsUtil.setFieldList(sourceBuilder, fieldList);
        // 限定索引
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        PageRequest  pageRequest= EsUtil.setPage(sourceBuilder, page, pageSize);
        XbbAggregatedPage<PaasFormDataEntityExt> xbbAggregatedPage  = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest,PaasFormDataEntityExt.class);
        List<PaasFormDataEntityExt> resultList = xbbAggregatedPage.getContent();
        long num = xbbAggregatedPage.getTotalElements();

        for (PaasFormDataEntityExt paasFormDataEntityExt : resultList) {
            paasFormDataEntityExt.setTagData(new JSONObject());
        }
        PageHelper pageHelper = new PageHelper(page, pageSize);
        pageHelper.setRowsCount((int) num);
        formDataListVO.setPaasFormDataESList(resultList);
        formDataListVO.setPageHelper(pageHelper);
        formDataListVO.setBusinessType(businessType);
        return formDataListVO;
    }

    @Override
    public <T> QueryListVO<T> list(IndexTypeEnum indexTypeEnum, SearchSourceBuilder sourceBuilder, List<String> fieldList, Integer page, Integer pageSize, Class clazz, String sortField, SortOrder order) throws XbbException {
        QueryListVO queryListVO = new QueryListVO();
        //限定返回值
        EsUtil.setFieldList(sourceBuilder, fieldList);
        // 字段排序
        if (StringUtil.isNotEmpty(sortField)) {
            sourceBuilder.sort(new FieldSortBuilder(sortField).order(order));
        }
        // 限定索引
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        PageRequest  pageRequest= EsUtil.setPage(sourceBuilder, page, pageSize);
        XbbAggregatedPage xbbAggregatedPage  = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest,clazz);
        long num = xbbAggregatedPage.getTotalElements();

        PageHelper pageHelper = new PageHelper(page, pageSize);
        pageHelper.setRowsCount((int) num);
        queryListVO.setDataList(xbbAggregatedPage.getContent());
        queryListVO.setPageHelper(pageHelper);
        return queryListVO;
    }

    @Override
    public <T> List<T> getDataList(BoolQueryBuilder boolQueryBuilder, IndexTypeEnum indexTypeEnum, List<String> fieldList, Integer page, Integer pageSize, Class<T> clazz, String sortField, SortOrder order) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        //限定返回值
        EsUtil.setFieldList(sourceBuilder, fieldList);
        // 分页
        PageRequest  pageRequest=  EsUtil.setPage(sourceBuilder, page, pageSize);
        sourceBuilder.query(boolQueryBuilder);
        // 限定索引
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());

        if (StringUtil.isNotEmpty(sortField)) {
            sourceBuilder.sort(new FieldSortBuilder(sortField).order(order));
        }
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<T> aggregatedPage = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, clazz);
        if (aggregatedPage == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return aggregatedPage.getContent();
    }

    @Override
    public <T> XbbAggregatedPage<T> getDataAndAggregation(BoolQueryBuilder boolQueryBuilder, AggregationBuilder aggregationBuilder, IndexTypeEnum indexTypeEnum, List<String> fieldList, Integer page, Integer pageSize, Class<T> clazz, String sortField, SortOrder order) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        //限定返回值
        EsUtil.setFieldList(sourceBuilder, fieldList);
        // 分页
        PageRequest  pageRequest = EsUtil.setPage(sourceBuilder, page, pageSize);
        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.aggregation(aggregationBuilder);
        // 限定索引
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());

        if (StringUtil.isNotEmpty(sortField)) {
            sourceBuilder.sort(new FieldSortBuilder(sortField).order(order));
        }
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<T> aggregatedPage = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, clazz);
        if (aggregatedPage == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return aggregatedPage;
    }

    @Override
    public long count(BoolQueryBuilder boolQueryBuilder, IndexTypeEnum indexTypeEnum) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        // 限定索引
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        CountRequest countRequest = new CountRequest(searchRequest.indices()[0]);
        countRequest.query(searchRequest.source().query());
        return xbbElasticsearchRestTemplate.count(countRequest);
    }

    @Override
    public List<PaasFormDataEntityExt> selectByOneCondition(Integer businessType, String attr, Object value, Map<String, Object> param, IndexTypeEnum indexTypeEnum) throws XbbException {
        Map<String, Object> dataParam = new HashMap<>(BasicConstant.ONE);
        dataParam.put(attr, value);
        return selectByCondition(businessType, dataParam, param, indexTypeEnum);
    }

    @Override
    public List<PaasFormDataEntityExt> selectByCondition(Integer businessType, Map<String, Object> dataParam, Map<String, Object> param, IndexTypeEnum indexTypeEnum) throws XbbException {
        if (!param.containsKey(StringConstant.CORPID)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        param.forEach((key, value) -> {
            if (Objects.equals(StringConstant.CORPID, key)) {
                boolQueryBuilder.filter(termQuery("corpid.keyword", value));
            } else if (Objects.equals(StringConstant.IDIN, key)) {
                List<Object> list = JSON.parseArray(JSON.toJSONString(value), Object.class);
                boolQueryBuilder.filter(termsQuery("dataId", list));
            } else if (Objects.equals("flowStatusIn", key)) {
                List<Object> list = JSON.parseArray(JSON.toJSONString(value), Object.class);
                boolQueryBuilder.filter(termsQuery("flowStatus", list));
            } else if (Objects.equals("delIn", key)) {
                List<Object> list = JSON.parseArray(JSON.toJSONString(value), Object.class);
                boolQueryBuilder.filter(termsQuery(StringConstant.DEL, list));
            } else if (Objects.equals("formIdIn", key)) {
                List<Object> list = JSON.parseArray(JSON.toJSONString(value), Object.class);
                boolQueryBuilder.filter(termsQuery(StringConstant.FORM_ID, list));
            } else if (Objects.equals("should", key)) {
                if (Objects.nonNull(value) && value instanceof Map) {
                    ((Map) value).forEach((k,v)->{
                        List<Object> list = JSON.parseArray(JSON.toJSONString(v), Object.class);
                        boolQueryBuilder.filter(termsQuery(k.toString(), list));
                    });
                }
            } else {
                boolQueryBuilder.filter(termQuery(key, value));
            }
        });
        if (Objects.nonNull(dataParam)) {
            dataParam.forEach((key, value) -> {
                String attr = StringConstant.JSON_DATA + StringConstant.POINT + key;
                if (attr.contains(FieldTypeEnum.TEXT.getEsalias())) {
                    // 为text开头加keyword
                    attr = attr + StringConstant.POINT + StringConstant.KEY_WORD;
                }
                if (value instanceof List) {
                    List<Object> list = JSON.parseArray(JSON.toJSONString(value), Object.class);
                    boolQueryBuilder.filter(termsQuery(attr, list));
                } else {
                    boolQueryBuilder.filter(termQuery(attr, value));
                }
            });
        }
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        //分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, EsNormalConstant.FIND_NUM);
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);
        if (esEntities == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return esEntities.getContent() == null ? new ArrayList<>() : esEntities.getContent();
    }


    @Override
    public void updateByMarketIdAndDel(List<Long> idList,String corpid, IndexTypeEnum indexTypeEnum,Integer del) throws XbbException {
        List<InsertDTO> insertList = new ArrayList<>();
        for ( Long id : idList ) {
            InsertDTO insertDTO = new InsertDTO();
            Map<String, Object> source = new HashMap(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            source.put("del", del);
            source.put("updateTime", DateUtil.getInt());
            insertDTO.setSource(source);
            insertDTO.setIndexTypeEnum(indexTypeEnum);
            insertDTO.setEsId(corpid + "_" + id);
            insertList.add(insertDTO);
        }
        updateBatch(insertList);
    }

    @Override
    public <T> List<T> getByDataIdList(List<Long> ids, IndexTypeEnum indexTypeEnum, Long formId, String corpid, Class<T> clazz, List<String> fieldList,   String sortField, SortOrder order) throws XbbException {

        if (CollectionsUtil.isEmpty(ids)) {
            return new ArrayList<>();
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        //限定返回值
        // 分页
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery("formId", formId));
        boolQueryBuilder.filter(termsQuery("dataId", ids));

        return getDataList(boolQueryBuilder, indexTypeEnum, fieldList, 1, ids.size(), clazz, sortField, order);
    }

    @Override
    public List<PaasFormDataEntityExt> dataListAndSubDataList(String corpid, Integer saasMark, Integer businessType, Long formId, List<Long> dataIdList, IndexTypeEnum indexTypeEnum) throws XbbException {
        //解析查询条件

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("formId", formId));
        boolQueryBuilder.filter(termsQuery(StringConstant.DATA_ID, dataIdList));
        boolQueryBuilder.filter(termQuery("del", 0));
        // 设置join_field
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 排序
        sourceBuilder.sort(new FieldSortBuilder(FieldTypeEnum.UPDATETIME.getAlias()).order(SortOrder.DESC));
        sourceBuilder.query(boolQueryBuilder);
        List<PaasFormDataEntityExt> list = list(sourceBuilder, indexTypeEnum, new ArrayList<>(), 1, dataIdList.size());
        // 设置子表单数据
        setSubFormData(list, corpid, saasMark, businessType, formId, indexTypeEnum);
        return list;
    }

    @Override
    public void setSubFormData(List<PaasFormDataEntityExt> list, String corpid, Integer saasMark, Integer businessType, Long formId, IndexTypeEnum indexTypeEnum) throws XbbException{
        if (CollectionsUtil.isNotEmpty(list)) {
            Set<Long> resultDataIdList = new HashSet<>();
            list.forEach(item->{
                resultDataIdList.add(item.getDataId());
            });
            IndexTypeEnum subIndexTypeEnum = IndexTypeEnum.getSubByIndexEnum(indexTypeEnum);
            List<PaasFormSubDataEntity> subDataList = paasFormSubDataEsModel.getSubDataByParentId(corpid, saasMark, businessType, formId, resultDataIdList, null, null, subIndexTypeEnum);
            FormSubDataUtil.setSubData(list, subDataList);
        }
    }

    /**
     * 物理删除
     * @param esId
     * @param index
     * @param type
     * @throws XbbException
     */
    private void physicalDelete(String esId,String index,String type ) throws XbbException {
        try {
            RestHighLevelClient client = xbbElasticsearchRestTemplate.getRestHighLevelClient(index);
            DeleteRequest deleteRequest = new DeleteRequest();
            //此处如果id为空直接捕获后抛出异常
            deleteRequest.id(esId)
                    .index(index);
            client.delete(deleteRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            LOG.error("es物理删除报错",e);
            throw  new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }
    }
    /**
     * 获取BulkRequest
     * @return
     */
    private BulkRequest getBulkRequest() {
        return getBulkRequest(WriteRequest.RefreshPolicy.WAIT_UNTIL);
    }

    private BulkRequest getBulkRequest(WriteRequest.RefreshPolicy refreshPolicy) {
        BulkRequest bulkRequest = Requests.bulkRequest();
        bulkRequest.setRefreshPolicy(refreshPolicy);
        return bulkRequest;
    }

    /**
     *Executes a bulk of index / delete operations.
     * @param bulkRequest
     * @throws XbbException
     */
    private void bulk(BulkRequest bulkRequest,String indexName) throws XbbException {
        bulk(bulkRequest,true,indexName);
    }
    private void bulk(BulkRequest bulkRequest,boolean needThrow,String indexName) throws XbbException {
        RestHighLevelClient client = xbbElasticsearchRestTemplate.getRestHighLevelClient(indexName);
        try {
            //TODO 注意同步和异步
            BulkResponse  bulkResponse= client.bulk(bulkRequest, RequestOptions.DEFAULT);
            printBulkError(bulkRequest, bulkResponse,needThrow);
        }catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("es报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    /**
     * 业务代码禁止使用
     * @param bulkRequest
     * @param needThrow
     * @param indexName
     * @throws XbbException
     */
    @Deprecated
    private void bulkAsync(BulkRequest bulkRequest,boolean needThrow,String indexName) throws XbbException {
        RestHighLevelClient client = xbbElasticsearchRestTemplate.getRestHighLevelClient(indexName);
        try {
            //TODO 注意同步和异步
            client.bulkAsync(bulkRequest, RequestOptions.DEFAULT, new ActionListener<BulkResponse>() {
                @SneakyThrows
                @Override
                public void onResponse(BulkResponse bulkItemResponses) {
                    printBulkError(bulkRequest, bulkItemResponses,needThrow);
                }

//                @SneakyThrows
                @Override
                public void onFailure(Exception e) {
                    LOG.error(SystemErrorCodeEnum.API_ERROR_100076.getMsg()+"==",e);
//                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100076, SystemErrorCodeEnum.API_ERROR_100076.getMsg());
                }
            });
        } catch (Exception e) {
            LOG.error("es报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    /**
     *  打印批量错误
     *  格式 esError===== + esId + 错误原因+ 错误数据
     *   esError=====xbbeca04bd4dba344ccb44090042b33809a_2336
     *   {"index":"idx_saas_customer_team","type":"saas_customer","id":"xbbeca04bd4dba344ccb44090042b33809a_2336","cause":{"type":"exception","reason":"Elasticsearch exception [type=mapper_parsing_exception, reason=failed to parse [data.text_18]]","caused_by":{"type":"exception","reason":"Elasticsearch exception [type=illegal_state_exception, reason=Can't get text on a START_OBJECT at 1:102]"}},"status":400}
     * index {[idx_saas_customer_team][saas_customer][xbbeca04bd4dba344ccb44090042b33809a_2336], source[{"formId":8313,"addTime":1568613801,"corpid":"xbbeca04bd4dba344ccb44090042b33809a","data":{"text_18":{},"text_1":0,"address_1":{"address":"","province":"","city":"","district":""},"text_16":"1493366979245","text_21":0,"date_2":0,"date_4":1568613809,"text_3":"","subForm_1":[{"text_1":"1","text_2":"1"},{"text_1":"2","text_2":"2"},{"text_1":"3","text_2":"3"},{"text_1":"4","text_2":"4"}],"text_4":"","num_1":0,"num_3":0,"num_4":2,"text_8":""},"departmentId":0,"creatorId":"1493366979245","del":0,"updateTime":1568613801,"ownerId":"1493366979245","serialNo":"","phoneStr":"","dataId":2336,"appId":2429,"menuId":9568,"id":2336,"flowStatus":0}]}
     * @param bulkRequest   入参
     * @param bulkResponse  返回数据
     * @throws XbbException  异常
     */
    private void printBulkError(BulkRequest bulkRequest, BulkResponse bulkResponse,boolean needThrow) throws XbbException {
        BulkItemResponse[] items = bulkResponse.getItems();
        for (int i = 0; i < items.length; i++) {
            BulkItemResponse bulkItemResponse  = items[i];
            if(bulkItemResponse.isFailed()){
                DocWriteRequest docWriteRequest = bulkRequest.requests().get(i);
                LOG.error(SystemErrorCodeEnum.API_ERROR_100076.getMsg() +"====="+ bulkItemResponse.getId()+"\n"+bulkItemResponse.getFailure()+"\n"+docWriteRequest);
                if(needThrow){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100076, SystemErrorCodeEnum.API_ERROR_100076.getMsg());
                }else {
                    break;
                }
            }
        }
    }

    private void update(UpdateRequest updateRequest) throws XbbException {
        RestHighLevelClient client = xbbElasticsearchRestTemplate.getRestHighLevelClient(updateRequest.index());
        try {
            client.update(updateRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            LOG.error("es更新报错",e);
            LOG.error(updateRequest.doc().toString());
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private IndexRequest getIndexRequest(InsertDTO insertDTO) throws Exception {
        return getIndexRequest(insertDTO,true);
    }
    private IndexRequest getIndexRequest(InsertDTO insertDTO,boolean needJoinField) throws Exception {
        IndexRequest indexRequest = new IndexRequest();
        Map<String, Object> source = insertDTO.getSource();
        //外面没传的才在此处处理
        if(needJoinField){
            IndexTypeEnum indexTypeEnum = insertDTO.getIndexTypeEnum();
            boolean isSubform = IndexTypeEnum.isSubform(indexTypeEnum);
            if (isSubform) {
                String relations = "{\"name\":\"" + indexTypeEnum.getType() + "\",\"parent\":\"" + insertDTO.getParent()  +"\"}";
                source.put(ElasticConstant.MY_JOIN_FIELD, JSONObject.parse(relations));
            } else {
                source.put(ElasticConstant.MY_JOIN_FIELD,insertDTO.getType());
            }
        }
        indexRequest
                .index(insertDTO.getIndex())
                .setRefreshPolicy(insertDTO.getWaitUntil())
                .source(JSON.toJSONString(source, SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect),Requests.INDEX_CONTENT_TYPE)
                .id(insertDTO.getEsId())
                .routing(insertDTO.getParent())
        ;
        return indexRequest;
    }

    private UpdateRequest getUpdateRequest(InsertDTO insertDTO) throws XbbException{
        UpdateRequest updateRequest = new UpdateRequest();
        Map<String, Object> source = insertDTO.getSource();
        if (Objects.isNull(source)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100077);
        }
        if (source.containsKey(StringConstant.DATA_ID)
                && Objects.isNull(source.get(StringConstant.DATA_ID))
                && Objects.nonNull(source.get(BusinessConstant.ID))) {
            source.put(StringConstant.DATA_ID, source.get(BusinessConstant.ID));
        }
        if (source.containsKey(BusinessConstant.ES_ID)
                && Objects.isNull(source.get(BusinessConstant.ES_ID)) && Objects.nonNull(insertDTO.getEsId())) {
            source.put(BusinessConstant.ES_ID, insertDTO.getEsId());
        }
        IndexTypeEnum indexTypeEnum = insertDTO.getIndexTypeEnum();
        boolean isSubform = IndexTypeEnum.isSubform(indexTypeEnum);
        if (isSubform) {
            String relations = "{\"name\":\"" + indexTypeEnum.getType() + "\",\"parent\":\"" + insertDTO.getParent()  +"\"}";
            source.put(ElasticConstant.MY_JOIN_FIELD, JSONObject.parse(relations));
        } else {
            source.put(ElasticConstant.MY_JOIN_FIELD,insertDTO.getType());
        }

        updateRequest.index(insertDTO.getIndex())
                .doc(JSON.toJSONString(source, SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect),Requests.INDEX_CONTENT_TYPE)
                .id(insertDTO.getEsId())
                .routing(insertDTO.getParent())
                .setRefreshPolicy(insertDTO.getWaitUntil())
                .retryOnConflict(5)
        ;
        return updateRequest;
    }

    private DeleteRequest getDeleteRequest(DeleteDTO deleteDTO) {
        IndexTypeEnum indexTypeEnum = deleteDTO.getIndexTypeEnum();
        DeleteRequest deleteRequest = new DeleteRequest();
        deleteRequest.index(indexTypeEnum.getIndex())
                .id(deleteDTO.getEsId())
                .setRefreshPolicy(deleteDTO.getWaitUntil())
                .routing(deleteDTO.getParent())
        ;
        return deleteRequest;
    }
}
